package com.crane.oss.sys.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crane.common.core.dto.Response;
import com.crane.common.core.dto.SingleResponse;
import com.crane.common.core.enums.ConstantEnums;
import com.crane.common.core.exception.AppException;
import com.crane.common.core.exception.BasicErrorCode;
import com.crane.common.core.utils.StringUtil;
import com.crane.common.framework.utils.BeanUtil;
import com.crane.oss.api.bean.resp.SchoolResp;
import com.crane.oss.api.constants.SynchronousRedisQueue;
import com.crane.oss.common.service.DistrictService;
import com.crane.oss.enums.PartyTypeEnum;
import com.crane.oss.enums.SchoolSystemEnum;
import com.crane.oss.enums.SectionEnum;
import com.crane.oss.enums.UserStatusEnum;
import com.crane.oss.school.bean.request.area.UpdateSchoolTimeReq;
import com.crane.oss.sports.XunFeiPushEventApiService;
import com.crane.oss.sys.bean.request.party.*;
import com.crane.oss.sys.bean.request.user.AddUserRequest;
import com.crane.oss.sys.bean.resp.PartyBean;
import com.crane.oss.sys.bean.resp.TreePartyBean;
import com.crane.oss.sys.dao.PartyDao;
import com.crane.oss.sys.dao.UserDao;
import com.crane.oss.sys.model.Party;
import com.crane.oss.properties.SysConfigProperties;
import com.crane.oss.sys.model.User;
import com.crane.oss.sys.service.PartyService;
import com.crane.oss.sys.service.UserPartyService;
import com.crane.oss.sys.service.UserService;
import com.crane.oss.xunfei.req.ApplySchoolReq;
import com.crane.oss.xunfei.resp.ApiSingleResponse;
import com.crane.utils.PinyinTool;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service("partyService")
public class PartyServiceImpl implements PartyService {

    private static final Logger logger = LoggerFactory.getLogger(PartyServiceImpl.class);

    @Resource
    protected PartyDao partyDao;

    @Resource
    private UserDao userDao;

    @Resource
    @Lazy
    UserService userService;

    @Resource
    protected UserPartyService userPartyService;

    @Resource
    DistrictService districtService;

    @Resource
    protected SysConfigProperties sysConfigProperties;

    @Resource
    XunFeiPushEventApiService xunFeiPushEventApiService;

    @Resource
    RedisTemplate redisTemplate;

    @Override
    public PartyBean queryParty(Long partyId) {
        logger.info("PartyServiceImpl queryViewBean partyId={}", partyId);
        Party party = partyDao.selectById(partyId);
        PartyBean partyBean = new PartyBean();
        BeanUtil.copyProperties(party, partyBean);
        if(null != partyBean.getParentId()){
            Party parentParty = partyDao.selectById(partyBean.getParentId());
            if(null != parentParty){
                partyBean.setParentName(parentParty.getNameCn());
            }
        }
        return partyBean;
    }

    @Override
    public IPage<PartyBean> queryList(QueryPartyRequest queryRequest) {
        logger.info("PartyServiceImpl queryList queryRequest={}", queryRequest);
        LambdaQueryWrapper<Party> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.likeLeft(StringUtil.isNotEmpty(queryRequest.getName()), Party::getNameCn, queryRequest.getName());
        queryWrapper.eq(StringUtil.isNotEmpty(queryRequest.getPartyCode()), Party::getPartyCode, queryRequest.getPartyCode());
        queryWrapper.eq(ObjectUtils.isNotNull(queryRequest.getParentId()), Party::getParentId, queryRequest.getParentId());
        queryWrapper.eq(ObjectUtils.isNotNull(queryRequest.getPartyType()), Party::getPartyType, queryRequest.getPartyType());
        queryWrapper.eq(ObjectUtils.isNotNull(queryRequest.getStatus()), Party::getStatus, queryRequest.getStatus());
        IPage<Party> page = partyDao.selectPage(new Page<>(queryRequest.getPageNo(), queryRequest.getPageSize()),queryWrapper);
        return page.convert(u -> {
            PartyBean v = new PartyBean();
            BeanUtils.copyProperties(u, v);
            return v;
        });
    }

    @Override
    public TreePartyBean queryPartyTree(QueryPartyTreeRequest request, Long opPartyId) {
        Long parentId = request.getParentId();
        if (parentId == null) {
            parentId = opPartyId;
        }
        Party parentParty = partyDao.selectById(parentId);
        if (org.springframework.util.ObjectUtils.isEmpty(parentParty)) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "父机构");
        }
        validatePartyRight(parentParty.getPartyId(),opPartyId,false);
        LambdaQueryWrapper<Party> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(Party ::getLineage,parentId);
        List<Party> partyList=partyDao.selectList(queryWrapper);
        TreePartyBean treePartyBean = new TreePartyBean();
        getTreeList(parentParty, partyList, treePartyBean);
        return treePartyBean;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public PartyBean save(AddPartyRequest addRequest) {
        logger.info("PartyServiceImpl save request={}", addRequest);
        Party parentParty = null;
        if (null != addRequest.getParentId()) {
            parentParty = partyDao.selectById(addRequest.getParentId());
            if (null == parentParty) {
                throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "上级机构");
            }
        }else{
            parentParty = partyDao.selectById(sysConfigProperties.getAdminPartyId());
            if (null == parentParty) {
                throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "上级机构");
            }
        }
        validatePartyRight(parentParty.getPartyId(),addRequest.getCreatePartyId(),false);
        int count= userDao.selectCount(Wrappers.lambdaQuery(User.class).eq(User ::getMobile,addRequest.getMobile()));
        if(count > 1){
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "该手机号码已注册");
        }
        count = userDao.selectCount(Wrappers.lambdaQuery(User.class).eq(User ::getUserName,addRequest.getMobile()));
        if(count > 1){
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "该手机号码已注册");
        }

        Party party = new Party();
        BeanUtil.copyProperties(addRequest, party);
        party.setAdminName(addRequest.getRealName());
        party.setParentId(parentParty.getPartyId());
        party.setLineage(parentParty.getLineage() + parentParty.getPartyId() + "|");
        party.setStatus(ConstantEnums.STATUS.VALID.getValue());
        party.setCreateTime(new Date());
        String partyCode= RandomStringUtils.randomNumeric(16);
        party.setPartyCode(partyCode);
        if(StringUtil.isNotEmpty(addRequest.getProvince())){
            party.setProvinceName(districtService.getNameByCode(addRequest.getProvince()));
        }
        if(StringUtil.isNotEmpty(addRequest.getCity())){
            party.setCityName(districtService.getNameByCode(addRequest.getCity()));
        }
        if(StringUtil.isNotEmpty(addRequest.getArea())){
            party.setAreaName(districtService.getNameByCode(addRequest.getArea()));
        }
        partyDao.insert(party);
        PartyBean partyBean=new PartyBean();
        BeanUtil.copyProperties(party, partyBean);
        //创建管理员
        AddUserRequest request=new AddUserRequest();
        if(StringUtil.isBlank(addRequest.getRealName())){
            request.setUserName(addRequest.getMobile());
        }else {
            String userName=userService.getUserName(addRequest.getRealName());
            request.setUserName(userName);
        }
        request.setRealName(addRequest.getRealNameSource());
        request.setMobile(addRequest.getMobile());
        request.setStatus(UserStatusEnum.VALID.getValue());
        request.setPartyCode(partyCode);
        request.setCreateUserId(addRequest.getCreateUserId());
        request.setCreatePartyId(addRequest.getCreatePartyId());
        userService.save(request);

        return partyBean;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(UpdatePartyRequest updateRequest) {
        logger.info("PartyServiceImpl update request={}", JSON.toJSON(updateRequest));
        Party party = partyDao.selectById(updateRequest.getId());
        if (null == party) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "party");
        }
        Party parentParty = partyDao.selectById(party.getParentId());
        if (null == parentParty) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "上级机构");
        }
        validatePartyRight(party.getPartyId(),updateRequest.getUpdatePartyId(),false);
        party.setUpdateTime(new Date());
        BeanUtil.copyProperties(updateRequest, party);
        if(StringUtil.isNotEmpty(updateRequest.getProvince())){
            party.setProvinceName(districtService.getNameByCode(updateRequest.getProvince()));
        }
        if(StringUtil.isNotEmpty(updateRequest.getCity())){
            party.setCityName(districtService.getNameByCode(updateRequest.getCity()));
        }
        if(StringUtil.isNotEmpty(updateRequest.getArea())){
            party.setAreaName(districtService.getNameByCode(updateRequest.getArea()));
        }
        partyDao.updateById(party);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long partyId,Long opPartyId) {
        logger.info("PartyServiceImpl delete partyId={}", partyId);
        Party party = partyDao.selectById(partyId);
        if (null == party) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "party");
        }
        validatePartyRight(partyId,opPartyId,false);
        partyDao.deleteById(partyId);
        //查询所有下级机构同时删除
        LambdaQueryWrapper<Party> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(Party ::getLineage,party.getPartyId());
        List<Party> partyList=partyDao.selectList(queryWrapper);
        for(Party temp : partyList){
            partyDao.deleteById(temp.getPartyId());
            userPartyService.deleteByPartyId(temp.getPartyId());
        }
    }

    @Override
    public List<PartyBean> queryPartyByUserId(Long id) {
        logger.info("PartyServiceImpl queryPartyByUserId id={}", id);
        List<Party> partyList = partyDao.queryPartyByUserId(id);
        return BeanUtil.copyList(partyList,PartyBean.class);
    }

    @Override
    public PartyBean queryPartyByCode(String code) {
        logger.info("PartyServiceImpl queryPartyByCode code={}", code);
        Party party = partyDao.selectOne(Wrappers.lambdaQuery(Party.class).eq(Party ::getPartyCode,code));
        if (party == null) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "机构");
        }
        if (party.getStatus().equals(ConstantEnums.STATUS.INVALID.getValue())) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "机构");
        }
        PartyBean partyBean = new PartyBean();
        BeanUtil.copyProperties(party, partyBean);
        return partyBean;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SingleResponse<PartyBean> saveSchool(AddSchoolPartyRequest request) {
        logger.info("PartyServiceImpl saveSchool request={}", request);
        Party parentParty = partyDao.selectById(request.getParentId());
        if (null == parentParty) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "上级机构");
        }
        validatePartyRight(parentParty.getPartyId(),request.getCreatePartyId(),false);
        User user= userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getMobile,request.getMobile()));
        if(null != user){
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "该手机号码已注册");
        }
        user = userDao.selectOne(Wrappers.lambdaQuery(User.class).eq(User ::getUserName,request.getMobile()));
        if(null != user){
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "该手机号码已注册");
        }

        Party party = new Party();
        party.setNameCn(request.getNameCn());
        party.setLogo(request.getLogo());
        party.setProvince(request.getProvince());
        party.setCity(request.getCity());
        party.setArea(request.getArea());
        if(StringUtil.isNotEmpty(request.getProvince())){
            party.setProvinceName(districtService.getNameByCode(request.getProvince()));
        }
        if(StringUtil.isNotEmpty(request.getCity())){
            party.setCityName(districtService.getNameByCode(request.getCity()));
        }
        if(StringUtil.isNotEmpty(request.getArea())){
            party.setAreaName(districtService.getNameByCode(request.getArea()));
        }
        party.setAdminName(request.getRealName());
        party.setAddress(request.getAddress());
        party.setTelephone(request.getTelephone());
        party.setMobile(request.getMobile());
        party.setSchoolType(request.getSchoolType());
        party.setSchoolSystem(request.getSchoolSystem());
        List<SectionEnum> result = SchoolSystemEnum.getSectionEnum(SchoolSystemEnum.getSchoolSystemEnum(request.getSchoolSystem().toString()));
        party.setSchoolPeriod(result.stream().map(o->o.getType().toString()).collect(Collectors.joining(",")));

        party.setCreateUserId(request.getCreateUserId());
        BeanUtil.copyProperties(request, party);
        party.setPartyType(PartyTypeEnum.SCHOOL.getType());
        party.setParentId(parentParty.getPartyId());
        party.setLineage(parentParty.getLineage() + parentParty.getPartyId() + "|");
        party.setStatus(ConstantEnums.STATUS.VALID.getValue());
        party.setCreateUserId(0L);
        party.setCreateTime(new Date());


        String partyCode= PinyinTool.convertHanzi2Pinyin(request.getNameCn(), true);
        int count=partyDao.selectCount(Wrappers.lambdaQuery(Party.class).eq(Party :: getPartyCode,partyCode));
        if(count != 0){
            partyCode =partyCode+ RandomStringUtils.randomNumeric(2);
        }
        party.setPartyCode(partyCode);
        partyDao.insert(party);
        PartyBean partyBean=new PartyBean();
        BeanUtil.copyProperties(party, partyBean);
        //创建管理员
        AddUserRequest addUserRequest=new AddUserRequest();
        if(StringUtil.isBlank(request.getRealName())){
            addUserRequest.setUserName(request.getMobile());
        }else {
            String userName=userService.getUserName(request.getRealName());
            addUserRequest.setUserName(userName);
        }
        addUserRequest.setRealName(request.getRealNameSource());
        addUserRequest.setMobile(request.getMobile());
        addUserRequest.setStatus(UserStatusEnum.VALID.getValue());
        addUserRequest.setPartyCode(partyCode);
        addUserRequest.setCreateUserId(request.getCreateUserId());
        addUserRequest.setCreatePartyId(request.getCreatePartyId());
        userService.save(addUserRequest);

        //审核
        ApplySchoolReq applySchoolReq=new ApplySchoolReq();
        applySchoolReq.setSchoolId(party.getPartyId().toString());
        applySchoolReq.setSchoolName(party.getNameCn());
        applySchoolReq.setSchoolCode(party.getPartyCode().toString());
        applySchoolReq.setAddress(party.getProvinceName()+party.getCityName()+party.getAreaName()+party.getAddress());
        String classSectionInfo="";
        for(String temp : request.getSchoolPeriod()){
            if(StringUtil.isNotEmpty(temp)){
                if(StringUtil.isEmpty(classSectionInfo)){
                    classSectionInfo=temp;
                }else{
                    classSectionInfo=classSectionInfo+","+SectionEnum.getRemarkByType(Integer.valueOf(temp));
                }
            }
        }
        applySchoolReq.setClassSectionInfo(classSectionInfo);
        applySchoolReq.setLengthOfSchool("6-3-3");
        ApiSingleResponse singleResponse=xunFeiPushEventApiService.applySchool(applySchoolReq,"","",addUserRequest.getCreateUserId().toString());
        if(null == singleResponse ||singleResponse.getCode() == 500){
            throw new AppException(BasicErrorCode.SYS_ERROR, "同步创建学校接口失败");
        }
        return SingleResponse.of(partyBean);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response updateSchool(UpdateSchoolPartyRequest request) {
        logger.info("PartyServiceImpl updateSchool request={}", request);
        boolean synchronousFlag = false;
        Party party = partyDao.selectById(request.getId());
        if (null == party) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "party");
        }
        validatePartyRight(party.getPartyId(),request.getUpdatePartyId(),false);
        if(StringUtil.isNotEmpty(request.getNameCn())){
            if(!request.getNameCn().equals(party.getNameCn())){
                synchronousFlag = true;
            }
            party.setNameCn(request.getNameCn());
        }
        if(StringUtil.isNotEmpty(request.getLogo())){
            party.setLogo(request.getLogo());
        }
        if(StringUtil.isNotEmpty(request.getProvince())){
            party.setProvince(request.getProvince());
            party.setProvinceName(districtService.getNameByCode(request.getProvince()));
        }
        if(StringUtil.isNotEmpty(request.getCity())){
            party.setCity(request.getCity());
            party.setCityName(districtService.getNameByCode(request.getCity()));
        }
        if(StringUtil.isNotEmpty(request.getArea())){
            party.setArea(request.getArea());
            party.setAreaName(districtService.getNameByCode(request.getArea()));
        }
        if(StringUtil.isNotEmpty(request.getAddress())){
            party.setAddress(request.getAddress());
        }
        if(StringUtil.isNotEmpty(request.getTelephone())){
            party.setTelephone(request.getTelephone());
        }
        if(ObjectUtils.isNotNull(request.getSchoolType())){
            party.setSchoolType(request.getSchoolType());
        }
        if(ObjectUtils.isNotNull(request.getSchoolSystem())){
            party.setSchoolSystem(request.getSchoolSystem());
            List<SectionEnum> result = SchoolSystemEnum.getSectionEnum(SchoolSystemEnum.getSchoolSystemEnum(request.getSchoolSystem().toString()));
            party.setSchoolPeriod(result.stream().map(o->o.getType().toString()).collect(Collectors.joining(",")));
        }
        party.setUpdateTime(new Date());
        partyDao.updateById(party);
        return Response.buildSuccess();
    }

    @Override
    public Response updateSchoolTime(UpdateSchoolTimeReq request) {
        logger.info("PartyServiceImpl updateSchool request={}", request);
        Party party = partyDao.selectById(request.getUpdatePartyId());
        if (null == party) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "party");
        }
        party.setUpdateTime(new Date());
        if(null != request.getSchoolStartTime()){
            party.setSchoolStartTime(request.getSchoolStartTime());
        }
        if(null != request.getSchoolEndTime()){
            party.setSchoolEndTime(request.getSchoolEndTime());
        }
        partyDao.updateById(party);
        return Response.buildSuccess();
    }

    @Override
    public Response updateSchoolState(Long id, Integer state) {
        Party party = partyDao.selectById(id);
        party.setStatus(state);
        party.setUpdateTime(new Date());
        partyDao.updateById(party);
        return Response.buildSuccess();
    }


    private void getTreeList(Party parentParty, List<Party> partyList, TreePartyBean treePartyBean) {
        if (null != parentParty) {
            bulidTreePartyBean(treePartyBean, parentParty);
        }
        for (Party party : partyList) {
            // 如果没有指定父节点,默认从 0 开始查找
            if (null == parentParty) {
                if (party.getParentId().equals(sysConfigProperties.getAdminPartyId())) {
                    getTreeList(party, partyList, treePartyBean);
                }
            } else if (party.getParentId().equals(parentParty.getPartyId())) {
                // 建立父子关系
                if (null == treePartyBean.getChildren()) {
                    List<TreePartyBean> children = new ArrayList<>();
                    treePartyBean.setChildren(children);
                }
                TreePartyBean childTreeMenuBean = new TreePartyBean();
                treePartyBean.getChildren().add(childTreeMenuBean);
                // 递归扫码子节点
                if (!party.getPartyType().equals(PartyTypeEnum.SCHOOL.getType())) {
                    getTreeList(party, partyList, childTreeMenuBean);
                } else {
                    bulidTreePartyBean(childTreeMenuBean, party);
                }
            }
        }
        // 对自己节点进行排序
        if (!CollectionUtils.isEmpty(treePartyBean.getChildren())) {
            Collections.sort(treePartyBean.getChildren());
        }
    }

    private void bulidTreePartyBean(TreePartyBean treePartyBean, Party party) {
        treePartyBean.setId(party.getPartyId());
        treePartyBean.setLabel(party.getNameCn());
        treePartyBean.setIsLeaf(false);
        treePartyBean.setPartyType(party.getPartyType());
        if (party.getPartyType().equals(PartyTypeEnum.SCHOOL.getType())) {
            treePartyBean.setIsLeaf(true);
        }
    }

    public PartyBean validatePartyRight(Long checkPartyId, Long opParty, Boolean flag) {
        logger.info("UserServiceImpl validateUserRight userId={}，flag={}", opParty, flag);
        if(checkPartyId.equals(opParty)){
            return this.queryParty(opParty);
        }
        PartyBean  opPartyBean = this.queryParty(opParty);
        PartyBean  checkPartyBean = this.queryParty(checkPartyId);
        if (checkPartyId.equals(opPartyBean.getPartyId())) {
            return checkPartyBean;
        }
        if (!flag) {
            String[] partIds = checkPartyBean.getLineage().split("\\|");
            for (String temp : partIds) {
                if (temp.equals(opParty.toString())) {
                    return checkPartyBean;
                }
            }
        }
        throw new AppException(BasicErrorCode.NO_DATA_RIGHT);
    }

}
